from _decimal import Decimal
from _pydecimal import Decimal
from typing import Dict, List, Any, Union

from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.users.models import Address

'''
订单

需求：　提交订单页面的展示

前端：　发送一个axios请求获取地址信息和购物车中选中的信息

后端：
    请求：　必须是登录用户才可以访问
    业务逻辑：　地址信息，购物车中选中商品信息
    响应：　JSON 
    路由：　GET  orders/settlement/
    步骤：　
        １．获取用户信息
        ２．地址信息
            ２．１查询用户地址信息[Adress]
            ２．２将对象数据转换为字典数据
        ３购物车中的商品信息
            ３．１连接redis
            ３．２hash  [sku_id:count,....]
            ３．３set　　[1,2]
            ３．４重新组织一个选中的信息
            ３．５根据商品id，查询商品的具体信息　[sku]
            ３．６需要将对象数据转换为字典数据
'''

from apps.users.models import Address
from utils.views import LoginRequiredJSONMixin
from apps.goods.models import SKU




class OrderSettlementView(LoginRequiredJSONMixin, View):

    def get(self, request):

        # １．获取用户信息
        user = request.user

        # ２．地址信息
        #     ２．１查询用户地址信息[Address]
        addresses = Address.objects.filter(user=request.user,
                                           is_deleted=False)

        #     ２．２将对象数据转换为字典数据
        addresses_list = []
        for address in addresses:
            addresses_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile
            })

          # ３购物车中的商品信息　添加管道
           #     ３．１连接redis
        redis_cli = get_redis_connection('carts')

        #     ３．２hash[sku_id:count, ....]

        sku_counts = redis_cli.hgetall('carts_%s' % user.id)

        #     ３．３set　　[1, 2]
        selected_ids = redis_cli.smembers('selected_%s' % user.id)

        #     ３．４重新组织一个选中的信息
        selected_carts = {}

        for sku_id in selected_ids:
            selected_carts[int(sku_id)]=int(sku_counts[sku_id])

            #     ３．５根据商品id，查询商品的具体信息　[sku]
        sku_list = []

        for sku_id, count in selected_carts.items():
            sku = SKU.objects.get(pk=sku_id)

            #     ３．６需要将对象数据转换为字典数据
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': count,
                'price': sku.price
            })

        context = {'sku': sku_list, 'addresses': addresses_list, 'freight': 10}
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'context': context})


'''
提交订单

保存订单的基本信息和订单商品信息

需求：　点击提交订单，生成订单

前端：　发送axios请求，POST　携带数据　（地址id，支付方式，携带用户的session信息（cookie))

后端：　

    请求：接收请求，验证数据
    业务逻辑：　数据入库
    响应：　返回响应
    路由：　ＰＯＳＴ
    步骤：
    
    一．接受请求　user,address_id,pay_method
    二．验证数据
     　order_id主键（自己生成）
    　支付状态由支付方式决定　
    　总数量，总金额，＝０
　　　　总运费
    三．数据入库　（生成订单（订单基本信息表和订单商品信息表）
        １　先保存订单基本信息
        ２　在保存订单商品信息
            ２．１连接redis 
            ２．２连接hash
            ２．３连接set
            ２．４遍历选中商品id
            　最好重写组织一个数据，这个数据是选中的商品信息
            　{sku_id:count,sku_id:count}
            ２．５根据选中商品的id进行查询
            ２．６判断库存是否充足
            ２．７如果库存充足，则库存减少，销量增加
            ２．８如果库存不足，下单失败
            ２．９累加总数量和总金额
            ２．１０　保存订单商品信息
        ３　更新订单的选中总金额和总数量
        ４　将redis中选中的商品信息移除出来
    四．返回响应

'''

import json
from apps.orders.models import OrderInfo, OrderGoods
from django.db import transaction



class OrderCommitView(LoginRequiredJSONMixin, View):
    def post(self, request):
        user = request.user

        #     一．接受请求　user, address_id, pay_method
        data = json.loads(request.body.decode())
        address_id = data.get('address_id')
        pay_method = data.get('pay_method')

        #     二．验证数据
        if not all([address_id, pay_method]):
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})

        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})

        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return JsonResponse({'code': 400, 'errmsg': '参数不正确'})

        #     　order_id主键（自己生成）
        from django.utils import timezone
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S%f') + '%09d' % user.id

        #     　支付状态由支付方式决定　
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        #     　总数量，总金额，＝０
        total_count = 0
        from decimal import Decimal
        total_amount = Decimal('0')

        #     　　　　总运费
        freight = Decimal('10.00')

        with transaction.atomic():
            # 事务开始点
            point = transaction.savepoint()

            #     三．数据入库　（生成订单（订单基本信息表和订单商品信息表）
            #     １　先保存订单基本信息
            orderinfo = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=total_count,
                total_amount=total_amount,
                freight=freight,
                pay_method=pay_method,
                status=status
            )
            #     ２　在保存订单商品信息
            #     ２．１连接redis
            redis_cli = get_redis_connection('carts')

            #     ２．２连接hash
            sku_id_counts = redis_cli.hgetall('carts_%s' % user.id)

            #     ２．３连接set
            select_ids = redis_cli.smembers('select_%s' % user.id)

            #     ２．４遍历选中商品id
            carts = {}

            for sku_id in select_ids:
                #     　最好重写组织一个数据，这个数据是选中的商品信息 {sku_id: count, sku_id: count}
                carts[int(sku_id)] = int(sku_id_counts[sku_id])

                #     ２．５根据选中商品的id进行查询
            for sku_id, count in carts.items():
                for i in range(10):
                    sku = SKU.objects.get(id=sku_id)

                    #     ２．６判断库存是否充足
                    if sku.stock < count:
                        # 事务的回滚点
                        transaction.savepoint_rollback(point)
                        # ２．８如果库存不足，下单失败
                        return JsonResponse({'code': 400, 'errmsg': '库存不足'})

                    from time import sleep
                    sleep(7)
                    #     ２．７如果库存充足，则库存减少，销量增加
                    # sku.stock -= count
                    # sku.sales += count
                    # sku.save()

                    # １．先记录一个数据，记录那个不重要
                    # 旧库存，参照这个记录
                    old_stock = sku.stock

                    # ２．我们更新的时候，在对比一下这个记录对不对
                    new_stock = sku.stock-count
                    new_sales = sku.sales+count

                    result = SKU.objects.filter(id=sku_id,stock=old_stock).updata(stock=new_stock,sales=new_sales)

                    if result==0:
                        sleep(0.005)
                        continue
                    #     ２．９累加总数量和总金额
                    orderinfo.total_count += count
                    orderinfo.total_amount -= (count * sku.price)

                    #     ２．１０　保存订单商品信息
                    OrderGoods.objects.create(
                        order=orderinfo,
                        sku=sku,
                        count=count,
                        price=sku.price
                    )

                # ３　更新订单的选中总金额和总数量
            orderinfo.save()
            transaction.savepoint_commit(point)
            # ４　将redis中选中的商品信息移除出来
        # 四．返回响应
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})
